use std::result;

use bcrypt::{hash, DEFAULT_COST};
use sqlx::{PgPool, Postgres, Transaction, Error};

use crate::{base::errors::AppError, data::{dto::user_dto::CreateUserRequest, model::user::User}, repository::QueryBuilder};

pub struct UserRepository;

/// 用户持久层
/// 
/// **作者：**张翔宇
/// **日期：**2025年9月1日
impl UserRepository {
    /// 创建新用户
    ///
    /// # 参数
    /// * `db_pool` - 数据库连接池
    /// * `name` - 用户名
    /// * `phone` - 手机号
    /// * `password_hash` - 密码哈希
    /// * `roles` - 用户角色列表
    ///
    /// # 返回
    /// 返回创建后的 User 实例或 AppError
    pub async fn create_user(tx: &mut Transaction<'_, Postgres>, user_id: &i64, request: CreateUserRequest) -> Result<User, AppError> {
        let hash_password = hash("abcd@1234", DEFAULT_COST)
            .map_err(|e| AppError::Runtime(e.to_string()))?;
        
        let user = sqlx::query_as::<_, User>(
        r#"
            INSERT INTO users ( username, avatar, gender, password_hash, phone, email, nick_name, is_active, created_by )
            VALUES
            ( $1, $2, $3, $4, $5, $6, $7, $8, $9 )
            RETURNING *
            "#
        )
        .bind(request.username)
        .bind(request.avatar)
        .bind(request.gender)
        .bind(hash_password)
        .bind(request.phone)
        .bind(request.email)
        .bind(request.nick_name)
        .bind(false)
        .bind(user_id)
        .fetch_one(&mut **tx)
        .await
        .map_err(|e| {
            AppError::Runtime(format!("创建用户失败: {}", e))
        })?;

        Ok(user)
    }

    /// 根据手机号查找用户
    ///
    /// # 参数
    /// * `db_pool` - 数据库连接池
    /// * `phone` - 手机号
    ///
    /// # 返回
    /// 返回 Option<User>，存在则为 Some(User)，否则为 None
    pub async fn find_by_phone(db_pool: &PgPool, phone: &str) -> Result<Option<User>, AppError> {
        sqlx::query_as::<_, User>(
            "SELECT id, name, phone, password_hash, roles, created_at, update_at FROM users WHERE id = $1"
        )
        .bind(phone)
        .fetch_optional(db_pool)
        .await
        .map_err(|e| AppError::Database(e.to_string()))
    }

    /// 根据用户名从数据库查询用户信息
    /// 
    /// # 参数
    /// * `db_pool` - PostgreSQL数据库连接池，用于获取数据库连接执行查询
    /// * `username` - 要查询的用户名
    /// 
    /// # 返回值
    /// * 成功时返回 `Result<Option<User>, AppError>`：
    ///   - 若存在该用户名的用户，返回 `Ok(Some(User))`
    ///   - 若不存在该用户名的用户，返回 `Ok(None)`
    ///   - 数据库操作失败时，返回 `Err(AppError::Database)` 包裹的错误信息
    pub async fn find_by_username(db_pool: &PgPool, username: &str) -> Result<Option<User>, AppError> {
        // 使用sqlx构建查询，将结果映射为User类型
        // SQL语句：查询users表中用户名等于指定值的记录
        sqlx::query_as::<_, User>(
            "SELECT * FROM users WHERE username = $1"
        )
        // 绑定参数：将username的值绑定到SQL语句中的$1占位符
        .bind(username)
        // 执行查询并获取可选结果（存在返回Some，不存在返回None）
        .fetch_optional(db_pool)
        // 等待异步查询完成
        .await
        // 将数据库原生错误转换为自定义的AppError类型
        .map_err(|e| AppError::Database(e.to_string()))
    }

    /// 根据用户ID查找用户
    ///
    /// # 参数
    /// * `db_pool` - 数据库连接池
    /// * `id` - 用户ID
    ///
    /// # 返回
    /// 返回 Option<User>，存在则为 Some(User)，否则为 None
    pub async fn find_by_id(db_pool: &PgPool, id: &i64) -> Result<Option<User>, AppError> {
        sqlx::query_as::<_, User>(
            "SELECT * FROM users WHERE id = $1"
        )
        .bind(id)
        .fetch_optional(db_pool)
        .await
        .map_err(|e| AppError::Database(e.to_string()))
    }

    /// 判断手机号是否已存在
    ///
    /// # 参数
    /// * `db_pool` - 数据库连接池
    /// * `phone` - 手机号
    ///
    /// # 返回
    /// 存在返回 true，否则返回 false
    pub async fn _phone_exists(db_pool: &PgPool, phone: &str) -> Result<bool, AppError> {
        sqlx::query_scalar::<_, bool>(
            "SELECT EXISTS(SELECT 1 FROM users WHERE phone = $1)",
        )
        .bind(phone)
        .fetch_one(db_pool)
        .await
        .map_err(|e| AppError::Database(e.to_string()))
    }

    /// 检查指定用户名在数据库中是否已存在
    /// 
    /// # 参数
    /// * `db_pool` - PostgreSQL数据库连接池，用于执行数据库查询操作
    /// * `username` - 需要检查的用户名字符串
    /// 
    /// # 返回值
    /// 成功时返回布尔值：`true`表示用户名已存在，`false`表示不存在；
    /// 失败时返回封装了数据库错误信息的`AppError`
    pub async fn username_exists(db_pool: &PgPool, username: &str) -> Result<bool, AppError> {
        sqlx::query_scalar::<_, bool>(
            "SELECT EXISTS(SELECT 1 FROM users WHERE username = $1)"
        )
        .bind(username)
        .fetch_one(db_pool)
        .await
        .map_err(|e| AppError::Database(e.to_string()))
    }

    /// 获取所有用户列表
    ///
    /// # 参数
    /// * `db_pool` - 数据库连接池
    ///
    /// # 返回
    /// 返回所有用户的 Vec<User>，或 AppError
    pub async fn list_users(db_pool: &PgPool) -> Result<Vec<User>, AppError> {
        sqlx::query_as::<_, User>(
            "SELECT id, name, phone, password_hash, roles, created_at, update_at FROM users"
        )
        .fetch_all(db_pool)
        .await
        .map_err(|e| AppError::Database(e.to_string()))
    }

    /// 获取用户分页数据
    /// 
    /// # 参数
    /// * `db_pool` - 数据库连接池，用于执行SQL查询
    /// * `size` - 每页显示的记录数量
    /// * `current` - 当前页码（从1开始）
    /// 
    /// # 返回值
    /// 成功时返回包含用户数据的Vec<User>，失败时返回AppError
    pub async fn page(db_pool: &PgPool, size: i32, current: i32, name: Option<&str>, phone: Option<&str>) -> Result<Vec<User>, AppError> {
        QueryBuilder::new()
            .sql("SELECT * FROM users".to_string())
            .like("username", name)
            .like("phone", phone)
            .not_equal("username", Some("Super"))
            .desc("created_at")
            .paginate(current, size)
            .query_all(db_pool)
            .await
            .map_err(|e| AppError::Database(format!("查询用户分页数据出错: {}", e)))
    }

    /// 获取用户总数
    /// 
    /// # 参数
    /// * `db_pool` - 数据库连接池，用于执行SQL查询
    /// 
    /// # 返回值
    /// 成功时返回用户总数（i64类型），失败时返回AppError
    pub async fn total(db_pool: &PgPool, name: Option<&str>, phone: Option<&str>) -> Result<i64, AppError> {
        QueryBuilder::new()
            .sql("SELECT COUNT(*) FROM users".to_string())
            .like("username", name)
            .like("phone", phone)
            .query_count(db_pool)
            .await
            .map_err(|e| AppError::Database(format!("查询用户分页数据出错: {}", e)))
    }

    pub async fn update_is_active_by_user_id(db_pool: &PgPool, id: &i64, is_active: &bool) -> Result<bool, Error> {
        let result = sqlx::query(
            "UPDATE users SET is_active = $1 WHERE id = $2"
        )
        .bind(is_active)
        .bind(id)
        .execute(db_pool)
        .await?;


        Ok(result.rows_affected() > 0)
    }

    /// 根据用户ID从数据库删除指定用户
    ///
    /// 执行DELETE语句删除users表中对应ID的用户记录，仅关注SQL操作是否成功（无对应ID时视为“操作完成”，不判定为错误）
    /// sqlx::query() 用于执行无返回结果集的 SQL（如 DELETE），搭配 execute() 方法获取「操作影响行数」
    /// 若用 fetch_one() 执行 DELETE，会因无结果集抛出「无行返回」错误，不符合写操作语义。
    /// 
    /// # 参数
    /// * `db_pool` - PostgreSQL数据库连接池，用于获取数据库连接以执行删除SQL
    /// * `id` - 待删除用户的唯一标识（用户ID），类型为`&i64`（避免所有权转移，提高传参效率）
    ///
    /// # 返回
    /// * 成功：返回 `Ok(())`，代表删除SQL已正常执行（包含“无对应ID用户”的场景，仅表示操作无异常）
    /// * 失败：返回 `Err(AppError::Database)`，封装数据库层面的错误信息（如连接失败、SQL语法错误、权限不足等）
    pub async fn delete_by_id(db_pool: &PgPool, id: &i64) -> Result<(), Error> {
        let _result = sqlx::query(
            "DELETE FROM users WHERE id = $1"
            )
            .bind(id)
            .execute(db_pool) // 执行删除操作（写操作专用方法），返回ExecuteResult（含受影响行数等信息）
            .await?;

        Ok(())
    }
}